#include <windows.h>
#include <cstring>
#include <string>
#include <cstdio>
#include <tchar.h>
#include "MyDirectInput8.h"
//tchar converting 
#include <atlbase.h>
#include <atlconv.h>
#include <detours.h>

#pragma comment( lib, "user32.lib" )
#pragma comment( lib, "detours.lib" )
#pragma comment ( lib, "Dxguid.lib" ) 
#define DLLEXPORT __declspec (dllexport)

const std::string GETCURSORPOSSERVERPIPENAME = _T("\\\\.\\pipe\\mGetCursorPosServerPipe");
namespace Mydll{

  //phototyping
  extern "C"{ 

  HRESULT WINAPI DirectInput8Create( HINSTANCE hinst,
        DWORD dwVersion,
        REFIID riidltf,
        LPVOID *ppvOut,
        LPUNKNOWN punkOuter
    ); 
  }
  //phototyping end


  HINSTANCE myHINSTANCE;
  // typedef struct _devicedata
  // {
  //   /* data */
  //   LONG MouseX;
  //   LONG MouseY;
  //   LONG MouseLClick;
  //   LONG MouseRClick;
  //   BYTE Keybd[256];
  //   LONG Valid;
  //   LONG BlockInput;
  // } Devicedata, *LPDevicedata;

  // Devicedata myDevicedata;

  typedef HRESULT (WINAPI *f_func)( 
      HINSTANCE hinst,
      DWORD dwVersion,
      REFIID riidltf,
      LPVOID *ppvOut,
      LPUNKNOWN punkOuter
  );
  HRESULT WINAPI DirectInput8Create ( 
      HINSTANCE hinst,
      DWORD dwVersion,
      REFIID riidltf,
      LPVOID *ppvOut,
      LPUNKNOWN punkOuter
  )
   {  
    HINSTANCE hGetProcIDDLL = LoadLibrary(TEXT("RealDINPUT8.DLL"));
    
    if (!hGetProcIDDLL) {
      MessageBox(0,TEXT("could not load the dynamic library"),TEXT("OAO"),0);   
      return EXIT_FAILURE;
    }
    
    f_func func = (f_func)GetProcAddress(hGetProcIDDLL, TEXT("DirectInput8Create"));
    if (!func) {
      MessageBox(0,TEXT("could not locate the function"),TEXT("OAO"),0);   
      return EXIT_FAILURE;
    }
    ///dynamic load RealDinput.dll done

    HRESULT hr=(HRESULT)func(hinst,dwVersion,riidltf,ppvOut,punkOuter);
    //GetModuleHandle(NULL)
    if(SUCCEEDED(hr))
    *ppvOut = new MyDirectInput8(reinterpret_cast<IDirectInput8*>(*ppvOut));

    return hr;
  }

//   BOOL WINAPI DllMain(
//     _In_  HINSTANCE hinstDLL,
//     _In_  DWORD fdwReason,
//     _In_  LPVOID lpvReserved
//   ){
     
//      char buf[128];

//      sprintf(buf,"%d",fdwReason);
//   myHINSTANCE=hinstDLL;
//     //  MessageBox(0,buf,"OWO",0);    
//       return TRUE;
//   }
}

BOOL (WINAPI *RealGetCursorPos)(
  _Out_  LPPOINT lpPoint
) = GetCursorPos;

NamedPipeServer *mGetCursorPosServerPipe=new NamedPipeServer(GETCURSORPOSSERVERPIPENAME);

BOOL WINAPI mGetCursorPos(_Out_  LPPOINT lpPoint){
  BOOL br=RealGetCursorPos(lpPoint);
  static LONG Mx;
  static LONG My;
  static BOOL MouseSet=FALSE;
        

  if(mGetCursorPosServerPipe->IsDataAvailable())
  {
    std::string message;
    if(mGetCursorPosServerPipe->Read(message))
    {
      //corp message
        std::stringstream ss(message);
        std::string opt;
        ss>>opt;
        if("clr"==opt){
          MouseSet=FALSE;
        }else if ("set" == opt){
          ss>>Mx>>My;
          MouseSet=TRUE;
        }
    }   
  }  
  if(TRUE == mGetCursorPosServerPipe->IsBroken()){
    delete mGetCursorPosServerPipe;
    mGetCursorPosServerPipe = new NamedPipeServer(GETCURSORPOSSERVERPIPENAME);
  }

  if(TRUE == MouseSet){
    lpPoint->x=(LONG)Mx;  
    lpPoint->y=(LONG)My;          
  }
    
  return br;
}

BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,
    DWORD fdwReason,
    LPVOID lpvReserved
)
{
  //USE                 User32.PostMessage(g, WMsg.WM_ACTIVATEAPP, (IntPtr)1, (IntPtr)1748); instead
//  MessageBoxA(0,"OAO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!","OUO",MB_OK);
    switch ( fdwReason ) {
        case DLL_PROCESS_ATTACH:                  
            DetourTransactionBegin();
            DetourUpdateThread( GetCurrentThread() );
            DetourAttach( &(PVOID &)RealGetCursorPos, mGetCursorPos );
            DetourTransactionCommit();
            break;

        case DLL_PROCESS_DETACH:
            DetourTransactionBegin();
            DetourUpdateThread( GetCurrentThread() );
            DetourDetach( &(PVOID &)RealGetCursorPos, mGetCursorPos );
            DetourTransactionCommit(); 
        break;
    }

    return TRUE;
}